<?php
namespace app\swoole\Console;

use app\swoole\TpSwooleCore;
use think\App;
use think\Config;
use think\console\Input;
use think\console\input\Argument;
use think\console\Output;
use think\exception\HttpResponseException;
use think\Hook;
use think\Lang;
use think\Loader;
use think\Log;
use think\Request;
use think\Response;
use think\Route;

class Command extends \think\console\Command
{
    private $basePath;
    private $swoole;

    private static $config;
    private static $request;
    protected static $dispatch;

    public function __construct($bathPath = null)
    {
        $this->basePath = $bathPath;
        parent::__construct('tp_swoole');
    }

    public function execute(Input $input, Output $output)
    {
        try {
            $action = $input->getArgument('action');

            switch ($action) {
                case 'start':
                    $this->start();
                    break;
                case 'stop':
                    $this->stop();
                    break;
                case 'restart':
                    $this->restart();
                    break;
                case 'reload':
                    $this->reload();
                    break;
                case 'info':
                    $this->showInfo();
                    break;
                default:
                    $help = <<<EOS

Usage: 
  [%s] ./bin/tp_swools [options] <action>

Arguments:
  action                start|stop|restart|reload|info|help

Options:
  -e, --env             The environment the command should run under, this feature requires Laravel 5.2+
  -d, --daemonize       Whether run as a daemon for "start & restart"
  -i, --ignore          Whether ignore checking process pid for "start & restart"
EOS;

                    $this->output->writeln(sprintf($help, PHP_BINARY));
                    break;
            }
        } catch (\Exception $e) {
            $error = sprintf(
                'Uncaught exception "%s"([%d]%s) at %s:%s, %s%s',
                get_class($e),
                $e->getCode(),
                $e->getMessage(),
                $e->getFile(),
                $e->getLine(),
                PHP_EOL,
                $e->getTraceAsString()
            );
        }
    }

    public function configure()
    {
        $this
            // 命令的名称 （"php console_command" 后面的部分）
            ->setName('tp_swoole')
            // 运行 "php console_command list" 时的简短描述
            ->setDescription('Create new model')
            // 运行命令时使用 "--help" 选项时的完整命令描述
            ->setHelp('This command allow you to create models...')
            ->addArgument('action');

    }

    public function start()
    {
        ini_set('display_errors', 'on');
        error_reporting(E_ALL);

//        try {
//            define('IS_CLI', PHP_SAPI == 'cli' ? FALSE : FALSE);
//        } catch (\Exception $e) {
//            var_dump($e->getTraceAsString());
//            var_dump($e->getMessage());
//            exit;
//        }

        $serverClass = \swoole_websocket_server::class;
        // 2. 执行应用
        $this->swoole = new $serverClass('127.0.0.1', 50001, \SWOOLE_PROCESS, \SWOOLE_SOCK_TCP);

        $settings = [
//            'daemonize'          => true,
            'dispatch_mode'      => 2,
            'reactor_num'        => function_exists('\swoole_cpu_num') ? \swoole_cpu_num() * 2 : 4,
            'worker_num'         => 20,
            'task_ipc_mode'      => 1,
            'task_max_request'   => 5000,
            'max_request'        => 3000,
            'open_tcp_nodelay'   => true,
            'pid_file'           => '/home/wwwlogs/swoole.pid',
            'log_file'           => '/home/wwwlogs/swoole.log',
            'request_slowlog_file' => '/home/wwwlogs/swoole_slow.log',
            'log_level'          => 3,
            'document_root'      => '',
            'buffer_output_size' => 2 * 1024 * 1024,
            'socket_buffer_size' => 128 * 1024 * 1024,
            'package_max_length' => 4 * 1024 * 1024,
            'reload_async'       => true,
            'max_wait_time'      => 60,
            'enable_reuse_port'  => true,
            'enable_coroutine'   => false,
            'http_compression'   => false,
        ];
        $this->swoole->set($settings);

        $this->swoole->on('Start', [$this, 'onStart']);
        $this->swoole->on('Shutdown', [$this, 'onShutdown']);
        $this->swoole->on('ManagerStart', [$this, 'onManagerStart']);
        $this->swoole->on('ManagerStop', [$this, 'onManagerStop']);
        $this->swoole->on('WorkerStart', [$this, 'onWorkerStart']);
        $this->swoole->on('WorkerStop', [$this, 'onWorkerStop']);
        $this->swoole->on('WorkerError', [$this, 'onWorkerError']);
        $this->swoole->on('PipeMessage', [$this, 'onPipeMessage']);
        $this->swoole->on('Request', [$this, 'onRequest']);
        $this->swoole->on('Message', [$this, 'onMessage']);

        $this->swoole->start();
        exit;

        // Here we go...
        //        self::$config = $this->getConfig();
        //
        //        $listenAt = sprintf('%s:%s', self::$config['listen_ip'], self::$config['listen_port']);
        //
        //        if (file_exists(self::$config['swoole']['pid_file'])) {
        //            $pid = (int)file_get_contents(self::$config['swoole']['pid_file']);
        //            if ($pid > 0 && App::kill($pid, 0)) {
        //                $this->warning(sprintf('Swoole[PID=%d] is already running at %s.', $pid, $listenAt));
        //                return 1;
        //            }
        //        }
        //
        //        if (self::$config['swoole']['daemonize']) {
        //            $this->output->writeln(sprintf('Swoole is running in daemon mode, and listening at %s, see "ps -ef|grep laravels".', $listenAt));
        //        } else {
        //            $this->output->writeln(sprintf('Swoole is listening at %s, press Ctrl+C to quit.', $listenAt));
        //        }
        //
        //        (new TpSwooleCore())->run(self::$config);
        //
        //        return 0;
    }

    public function onStart()
    {
        echo 123;
    }

    public function onShutdown()
    {
        echo "shutdown";
    }

    public function onManagerStart()
    {
        echo "managerStart";
    }

    public function onManagerStop()
    {
        echo "managerStop";
    }

    public function onWorkerStart()
    {
        \app\swoole\Console\App::workStart();
    }

    public function handleFatal()
    {
        $error = error_get_last();
        if (isset($error['type']))
        {
            switch ($error['type'])
            {
                case E_ERROR :
                case E_PARSE :
                case E_CORE_ERROR :
                case E_COMPILE_ERROR :
                    $message = $error['message'];
                    $file = $error['file'];
                    $line = $error['line'];
                    $log = "$message ($file:$line)\nStack trace:\n";
                    $trace = debug_backtrace();
                    foreach ($trace as $i => $t)
                    {
                        if (!isset($t['file']))
                        {
                            $t['file'] = 'unknown';
                        }
                        if (!isset($t['line']))
                        {
                            $t['line'] = 0;
                        }
                        if (!isset($t['function']))
                        {
                            $t['function'] = 'unknown';
                        }
                        $log .= "#$i {$t['file']}({$t['line']}): ";
                        if (isset($t['object']) and is_object($t['object']))
                        {
                            $log .= get_class($t['object']) . '->';
                        }
                        $log .= "{$t['function']}()\n";
                    }
                    if (isset($_SERVER['REQUEST_URI']))
                    {
                        $log .= '[QUERY] ' . $_SERVER['REQUEST_URI'];
                    }
                    error_log($log);
                    $serv->send($this->currentFd, $log);
                default:
                    break;
            }
        }
    }

    public function onWorkerStop()
    {
        echo "onWorkerStop";
    }

    public function onWorkerError()
    {
        echo "onWorkerError";
    }

    public function onPipeMessage()
    {
        echo "onPipeMessage";
    }

    public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame)
    {
       echo "onMessage";
    }

    public function onRequest($request, $response)
    {
        echo 1;
        try {
            $_GET = $request->get;
            $_POST = $request->post;
            $_SERVER = $request->server;

            $result = \app\swoole\Console\App::receive();
            $header = $result['header'];
            $content = $result['content'];
//            var_dump($result, $header);
            foreach ($header as $key => $value) {
                $response->header($key, $value);
            }
            $response->end($content);
        } catch (\Exception $e) {
            error_log($e->getMessage());
            $response->end($e->getMessage() . ':' . $e->getFile() . ':' . $e->getLine());
        } catch (\Throwable $e) {
            error_log($e->getMessage());
            $response->end($e->getMessage() . ':' . $e->getFile() . ':' . $e->getLine());
        }
        return;
    }

//    public function getConfig()
//    {
//        self::$config = include $this->basePath . '/application/swoole/Config/swoole.php';
//        return self::$config;
//    }
}